#ifndef __SYS_PTHREAD_H
#define __SYS_PTHREAD_H

#include <stddef.h>
#include <stdint.h>
#include <sys/mutexqueue.h>
#include <arch/atomic.h>
#include <sys/time.h>

typedef uint64_t pthread_t;

//pthread control
#define PTHREAD_PROCESS_PRIVATE 0
#define PTHREAD_PROCESS_SHARE 1

//pthread stack argument
#define PTHREAD_STACKSIZE_MIN (16 * 1024) //min stacksize
//default stacksize
#define PTHREAD_STACKSIZE_DEF PTHREAD_STACKSIZE_MIN

//boot state
#define PTHREAD_CREATE_DETACHED 1 //detach
#define PTHREAD_CREATE_JOINABLE 0 //general

//pthread cancel state
#define PTHREAD_CANCEL_ENABLE 1
#define PTHREAD_CANCEL_DISABLE 0

//pthread cancel type
#define PTHREAD_CANCEL_DEFFERED 0    //continue run until next cancel point do exit
#define PTHREAD_CANCEL_ASYCHRONOUS 1 //do execv cancel now

//pthread attr
typedef struct _pthread_attr
{
    int detachstate; //detach state
    void *stackaddr; //stack addr
    int stacksize;   //stack size
} pthread_attr_t;

//pthread spinlock
typedef struct _pthread_spinlock
{
    atomic_t count; //0:unlock 1:lock
    int pshared;    //if use in muitithread
} pthread_spinlock_t;

#define PTHREAD_SPIN_LOCK_INITIALIZER           \
    {                                           \
        ATOMIC_INIT(0), PTHREAD_PROCESS_PRIVATE \
    }

typedef struct _pthread_mutexattr
{
    int pshared;
    int type; //metex attr type
} pthread_mutexattr_t;

//mutex lock
#define PTHREAD_MUTEX_NORMAL 1                     //normal mutex
#define PTHREAD_MUTEX_ERRORCHECK 2                 //error check
#define PTHREAD_MUTEX_RECURSIVE 3                  //process can request lock reapt
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL //default lock

//default init to no init lock
#define PTHREAD_MUTEX_ATTR_INITIALIZER                 \
    {                                                  \
        PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_DEFAULT \
    }

//default init to no init lock
#define PTHREAD_MUTEX_INITIALIZER                                                                                                                                          \
    {                                                                                                                                                                      \
        .lock = 1, .count = 0, .owner = 0, .kind = PTHREAD_MUTEX_DEFAULT, .mutex_queue = -1, .spin = PTHREAD_SPIN_LOCK_INITIALIZER, .attr = PTHREAD_MUTEX_ATTR_INITIALIZER \
    }

typedef struct _pthread_condattr
{
    int pshared;
} pthread_condattr_t;

typedef struct _phread_cond
{
    pthread_spinlock_t spin;      //spinlock
    int mutex_queue;              //wait queue
    pthread_condattr_t cond_attr; //attr
} pthread_cond_t;

//default init to no init lock
#define PTHREAD_COND_ATTR_INITIALIZER \
    {                                 \
        PTHREAD_PROCESS_PRIVATE       \
    }
#define PTHREAD_COND_INITIALIZER                                                                             \
    {                                                                                                        \
        .spin = PTHREAD_SPIN_LOCK_INITIALIZER, .mutex_queue = -1, .cond_attr = PTHREAD_COND_ATTR_INITIALIZER \
    }

//pthread mutex
typedef struct _pthread_mutex
{
    int owner;                //lock owner
    int lock;                 //lock val 0:lock 1:unlock
    int count;                //lock count
    int kind;                 //lock type
    int mutex_queue;          //wait queue
    pthread_spinlock_t spin;  //spinlock
    pthread_mutexattr_t attr; //pthread mutex attr
} pthread_mutex_t;

int pthread_make_default_attr(pthread_attr_t *attr);
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
void pthread_exit(void *ret);
void __pthread_exit(void *ret);
int pthread_detach(pthread_t thread);
int pthread_join(pthread_t thread, void **thread_ret);
pthread_t pthread_self();
int pthread_equal(pthread_t thread1, pthread_t thread2);
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
int pthread_testcancel(void);

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr);
void _pthread_cleanup_push(void (*cleanup)(void *), void *arg);
void _pthread_cleanup_pop(int execute);

int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);
int pthread_spin_is_locked(pthread_spinlock_t *lock);

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type);

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timeout(pthread_cond_t *cond, pthread_mutex_t *mutex, const timespec_t *abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);

#endif